#include "window.h"

Window::Window(GLsizei w, GLsizei h, ADSShader * shader, DMShader * dm_shader)
{
	this->window_handle = -1;
	this->width = w;
	this->height = h;
	this->shader = shader;
	this->dm_shader = dm_shader;
	this->period = 1000 / 60;
	this->x = this->y = 0;
	this->wallpaper = WALLPAPER_1;
	this->planar_mesh1 = NULL;
	this->planar_mesh2 = NULL;
	this->cube_mesh = NULL;
	this->wireframe = false;
	this->draw_normals = false;
	this->force_open = false;
	this->InitializeGLHandles();
	this->do_normal_mapping = false;
	this->do_texture_mapping = false;
	this->mode = ORANGE_BEAUTY;
	this->sourcePosition = glm::vec2(0, 0);
	this->destinationPosition = glm::vec2(0, 0);
	this->destinationSet = false;
	this->drewDestinationSet = false;

}

static int currentColorAttachment = 0;
static int previousColorAttachment = 0;
static int doublePreviousColorAttachment = 0;
static bool firstDraw = true;
static bool wallpaperSwitched = false;



void Window::SetupHandles(GLuint * array_handle, PlanarMesh * mesh)
{
	//Specifies number of buffer object names to be generated and places in vertex_coordinate_handle
	glGenBuffers(1, &this->vertex_coordinate_handle);
	assert(this->vertex_coordinate_handle != BAD_GL_VALUE);
	//Bind it to gl_array_buffer
	glBindBuffer(GL_ARRAY_BUFFER, this->vertex_coordinate_handle);
	//Creates and initializes a buffer object's data store
	glBufferData(GL_ARRAY_BUFFER, mesh->GetSizeOfArray() * sizeof(glm::vec3), mesh->GetOutArray(), GL_STATIC_DRAW);

	glGenBuffers(1, &this->texture_coordinate_handle);
	assert(this->texture_coordinate_handle != BAD_GL_VALUE);
	glBindBuffer(GL_ARRAY_BUFFER, this->texture_coordinate_handle);
	glBufferData(GL_ARRAY_BUFFER, mesh->GetSizeOfArray() * sizeof(glm::vec2), mesh->GetOutTextureCoordinates(), GL_STATIC_DRAW);

	glGenBuffers(1, &this->normal_value_handle);
	assert(this->normal_value_handle != BAD_GL_VALUE);
	glBindBuffer(GL_ARRAY_BUFFER, this->normal_value_handle);
	glBufferData(GL_ARRAY_BUFFER, mesh->GetSizeOfArray() * sizeof(glm::vec3), mesh->GetOutNormals(), GL_STATIC_DRAW);

	//Generates vertex array object names
	glGenVertexArrays(1, array_handle);
	//Binds vertex array object with array_handle
	glBindVertexArray(*array_handle);


	glEnableVertexAttribArray(0); //vertex
	glEnableVertexAttribArray(1); //normal
	glEnableVertexAttribArray(2); //texture

	glBindBuffer(GL_ARRAY_BUFFER, this->vertex_coordinate_handle);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte *) NULL);
	glBindBuffer(GL_ARRAY_BUFFER, this->normal_value_handle);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte *) NULL);
	glBindBuffer(GL_ARRAY_BUFFER, this->texture_coordinate_handle);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLubyte *) NULL);

	glBindVertexArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}

bool Window::PostGLInitialize(void * data, Mode mode)
{
	WindowStruct * mws = (WindowStruct *) data;
	this->cube_mesh = new PlanarMesh(200, 200);
	this->planar_mesh1 = new PlanarMesh(mws->grid_size1.x, mws->grid_size1.y, mws->open);
	this->planar_mesh2 = new PlanarMesh(mws->grid_size2.x, mws->grid_size2.y, mws->open);
	this->ApplyCustomization(mws->function1, planar_mesh1);
	this->ApplyCustomization(mws->function2, planar_mesh2);

	if (this->normal_map_container.Initialize("NMBumpsOut.png") == false)
	{
		cerr << "Failed to load normal map texture." << endl;
		return false;
	}

	if (this->wallpaper1_container.Initialize("Wallpaper.jpg") == false)
	{
		cerr << "Failed to load Wallpaper1.jpg texture." << endl;
		return false;
	}

	if (this->wallpaper2_container.Initialize("Wallpaper2.jpg") == false)
	{
		cerr << "Failed to load Wallpaper2.jpg texture." << endl;
		return false;
	}

	if (this->wallpaper3_container.Initialize("Wallpaper3.jpg") == false)
	{
		cerr << "Failed to load Wallpaper3.jpg texture." << endl;
		return false;
	}

	if (this->buckyTex_container.Initialize("buckyBadger.jpg") == false)
	{
		cerr << "Failed to load buckyBadger.jpg" <<endl;
		return false;
	}

	if (this->wood1_container.Initialize("Wood1.jpg") == false)
	{
		cerr << "Failed to load buckyBadger.jpg" <<endl;
		return false;
	}

	if (!this->ADS_shader.Initialize("per_fragment.vert", "per_fragment.frag"))
		return false;

	this->shader = &this->ADS_shader;

	if (!this->DM_shader.Initialize("dm.vert", "dm.frag"))
		return false;

	this->dm_shader = &this->DM_shader;

	SetupHandles(&this->planar_mesh_1_handle, this->planar_mesh1);

	SetupHandles(&this->planar_mesh_2_handle, this->planar_mesh2);

	SetupHandles(&this->cube_vertex_array_handle, this->cube_mesh);

	return true;
}

void Window::SetupShader(glm::mat4 projection_matrix, 
		glm::mat4 modelview_matrix, glm::mat3 normal_matrix, glm::mat4 mvp_matrix)
{
	shader->Use();

	SetTexture();

	glUniform1i(shader->source_handlex, this->sourcePosition.x);
	glUniform1i(shader->source_handley, this->sourcePosition.y);
	glUniform1i(shader->destination_handlex, this->destinationPosition.x);
	glUniform1i(shader->destination_handley, this->destinationPosition.y);
	glUniform1i(shader->window_width_handle, 1280);
	glUniform1i(shader->window_height_handle, 800);

	glUniform1i(shader->do_displacement_mapping, this->do_displacement_mapping);
	glUniform1i(shader->do_normal_mapping_handle, this->do_normal_mapping);
	glUniform1i(shader->do_texture_mapping_handle, this->do_texture_mapping);
	glUniformMatrix4fv(shader->projection_matrix_handle, 1, GL_FALSE, glm::value_ptr(projection_matrix));
	glUniformMatrix4fv(shader->modelview_matrix_handle, 1, GL_FALSE, glm::value_ptr(modelview_matrix));
	glUniformMatrix4fv(shader->mvp_handle, 1, GL_FALSE, glm::value_ptr(mvp_matrix));
	glUniformMatrix3fv(shader->normal_matrix_handle, 1, GL_FALSE, glm::value_ptr(normal_matrix));

	//Do not modify this, instead modify the materials
	shader->SetLight(glm::vec4(100.0f, 100.0f, 100.0f,1.0f), glm::vec3(1.0f), glm::vec3(1.0f), glm::vec3(1.0f));
}

void Window::SetupDMShader(glm::mat4 projection_matrix, 
		glm::mat4 modelview_matrix, glm::mat3 normal_matrix, glm::mat4 mvp_matrix)
{

	dm_shader->Use();

	glUniform1i(dm_shader->source_handlex, this->sourcePosition.x);
	glUniform1i(dm_shader->source_handley, this->sourcePosition.y);
	glUniform1i(dm_shader->destination_handlex, this->destinationPosition.x);
	glUniform1i(dm_shader->destination_handley, this->destinationPosition.y);

	glUniform1i(dm_shader->window_width_handle, this->width);
	glUniform1i(dm_shader->window_height_handle, this->height);

	glUniformMatrix4fv(dm_shader->projection_matrix_handle, 1, GL_FALSE, glm::value_ptr(projection_matrix));
	glUniformMatrix4fv(dm_shader->modelview_matrix_handle, 1, GL_FALSE, glm::value_ptr(modelview_matrix));
	glUniformMatrix4fv(dm_shader->mvp_handle, 1, GL_FALSE, glm::value_ptr(mvp_matrix));
	glUniformMatrix3fv(dm_shader->normal_matrix_handle, 1, GL_FALSE, glm::value_ptr(normal_matrix));

}

void Window::InitializeMatrices()
{
	float theta = ((float) this->x) / ((float) this->width) * 360.0f - 180.0f;
	float rho = ((float) this->y) / ((float) this->height) * 360.0f - 180.0f;

	//Set initial value to matrices
	glm::mat4 projection_matrix = glm::perspective(20.0f, ((float) this->width) / ((float) this->height), 1.0f, 10.0f);
	glm::mat4 modelview_matrix = glm::rotate(glm::rotate(glm::lookAt(glm::vec3(0.0f, 0.0f, 5.5f), glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)), theta, glm::vec3(0.0f, 1.0f, 0.0f)), rho, glm::vec3(1.0f, 0.0f, 0.0f));
	glm::mat3 normal_matrix = glm::inverse(glm::transpose(glm::mat3(modelview_matrix)));
	glm::mat4 mvp_matrix = projection_matrix * modelview_matrix;

	//set up the orange shader
	SetupShader(projection_matrix, modelview_matrix, normal_matrix, mvp_matrix);
}

//Combine DrawOrange() and DrawBottle into 'DrawBeautyMode'???
void Window::DrawOrange()
{
	do_normal_mapping = true;

	//Initialize the matrices
	this->InitializeMatrices();

	//Set the material to orange
	shader->SetMaterial(glm::vec3(.13f), glm::vec3(1.0f, .549f, 0.0f), glm::vec3(1.0f, .549f, 0.0f), 80.0f);

	glBindVertexArray(this->planar_mesh_1_handle);
	glDrawElements(GL_TRIANGLES , this->planar_mesh1->GetNumberOfElements(), GL_UNSIGNED_INT , this->planar_mesh1->GetTriangleIndexArray());

	this->DrawNormals(planar_mesh1);

	//Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);
	do_normal_mapping = false;
}

void Window::DrawBottle()
{
	do_texture_mapping = true;

	this->InitializeMatrices();

	//Set the material to orange
	shader->SetMaterial(glm::vec3(.5f), glm::vec3(1.0f, .5f, .7f), glm::vec3(1.0f, .549f, .3f), 80.0f);

	glBindVertexArray(this->planar_mesh_2_handle);
	glDrawElements(GL_TRIANGLES , this->planar_mesh2->GetNumberOfElements(), GL_UNSIGNED_INT , this->planar_mesh2->GetTriangleIndexArray());

	this->DrawNormals(planar_mesh2);

	//Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);
	do_texture_mapping = false;

}

void Window::DrawCube(glm::mat4 modelview_matrix)
{
	int i;

	// save the modelview matrix at the center of the cube
	glm::mat4 modelview_center = modelview_matrix;

	// draw the 4 sides of the cube
	for (i = 0; i < 4; i++)
	{
		// rotate and translate to draw face
		modelview_matrix = glm::rotate(modelview_matrix, 90.0f, glm::vec3(0.0f, 1.0f, 0.0f));
		this->DrawFace(glm::translate(modelview_matrix, glm::vec3(0.0f, 0.0f, 0.5f)));
	}

	// draw top face
	modelview_matrix = glm::rotate(modelview_center, 90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
	this->DrawFace(glm::translate(modelview_matrix, glm::vec3(0.0f, 0.0f, 0.5f)));

	// draw bottom face
	modelview_matrix = glm::rotate(modelview_center, -90.0f, glm::vec3(1.0f, 0.0f, 0.0f));
	this->DrawFace(glm::translate(modelview_matrix, glm::vec3(0.0f, 0.0f, 0.5f)));
}

void Window::DrawFace(glm::mat4 modelview_matrix)
{
	do_texture_mapping = true;
	// set up the standard matricies
	glm::mat4 projection_matrix = glm::perspective(20.0f, ((float) this->width) / ((float) this->height), 1.0f, 100.0f);
	glm::mat3 normal_matrix = glm::inverse(glm::transpose(glm::mat3(modelview_matrix)));
	glm::mat4 mvp_matrix = projection_matrix * modelview_matrix;

	// Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);

	// set up the shader
	SetupShader(projection_matrix, modelview_matrix, normal_matrix, mvp_matrix);

	//Set the material to orange
	shader->SetMaterial(glm::vec3(0.5f), glm::vec3(0.5f), glm::vec3(0.5f), 80.0f);

	// draw the face
	glBindVertexArray(this->cube_vertex_array_handle);
	glDrawElements(GL_TRIANGLES , this->cube_mesh->GetNumberOfElements(), GL_UNSIGNED_INT , this->cube_mesh->GetTriangleIndexArray());

	this->DrawNormals(cube_mesh);
	do_texture_mapping = false;
}

void Window::DrawToFrameBuffer(Wallpaper wallpaper, glm::mat4 modelview_matrix)
{
	//fbo.Bind(currentColorAttachment);
	//fbo.Bind(1);
	do_texture_mapping = true;

	glm::mat4 projection_matrix = glm::ortho(-.5f, .5f, -.5f, .5f, 0.0f, 20.0f);
	glm::mat3 normal_matrix = glm::inverse(glm::transpose(glm::mat3(modelview_matrix)));
	glm::mat4 mvp_matrix = projection_matrix * modelview_matrix;
	
	// Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);

	// set up the orange shader
	SetupShader(projection_matrix, modelview_matrix, normal_matrix, mvp_matrix);

	// set the material to white because it will be retextured with a picture
	shader->SetMaterial(glm::vec3(1.0f), glm::vec3(1.0f), glm::vec3(1.0f), 80.0f);

	glBindVertexArray(this->cube_vertex_array_handle);
	glDrawElements(GL_TRIANGLES , this->cube_mesh->GetNumberOfElements(), GL_UNSIGNED_INT , this->cube_mesh->GetTriangleIndexArray());
	this->DrawNormals(cube_mesh);

	// Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);
	do_texture_mapping = false;
	//fbo.Unbind();
}

void Window::DrawDM()
{
	//fbo.Bind(currentColorAttachment);
	fbo.Bind(0);

	glm::mat4 modelview_matrix = glm::mat4(1.0f);
	glm::mat4 projection_matrix = glm::ortho(-.5f, .5f, -.5f, .5f, 0.0f, 20.0f);
	glm::mat3 normal_matrix = glm::inverse(glm::transpose(glm::mat3(modelview_matrix)));
	glm::mat4 mvp_matrix = projection_matrix * modelview_matrix;
	
	// Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);

	// set up the orange shader
	SetupDMShader(projection_matrix, modelview_matrix, normal_matrix, mvp_matrix);

	glBindVertexArray(this->cube_vertex_array_handle);
	glDrawElements(GL_TRIANGLES , this->cube_mesh->GetNumberOfElements(), GL_UNSIGNED_INT , this->cube_mesh->GetTriangleIndexArray());

	this->DrawNormals(cube_mesh);

	// Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);
	fbo.Unbind();

	if (destinationSet)
	{
		this->drewDestinationSet = true;
	}

	else
	{
		this->drewDestinationSet = false;
	}

}

void Window::DrawBackGround()
	
{
	glm::mat4 projection_matrix = glm::ortho(-.5f, .5f, -.5f, .5f, 0.0f, 20.0f);
	glm::mat4 modelview_matrix = glm::mat4(1.0f);
	modelview_matrix = glm::translate(modelview_matrix, glm::vec3(0, 0, -5));
	glm::mat3 normal_matrix = glm::inverse(glm::transpose(glm::mat3(modelview_matrix)));
	glm::mat4 mvp_matrix = projection_matrix * modelview_matrix;

	this->do_displacement_mapping = true;

	//comment 
    this->DrawDM();

	CyclecurrentColorAttachment();

	this->DrawToFrameBuffer(wallpaper, modelview_matrix);

	/*firstDraw = false;

	CyclecurrentColorAttachment();

	this->do_texture_mapping = true;
	this->do_displacement_mapping = false;
	
	// set up the orange shader
	SetupShader(projection_matrix, modelview_matrix, normal_matrix, mvp_matrix);

	// set the material to white because it will be retextured with a picture
	shader->SetMaterial(glm::vec3(1.0f), glm::vec3(1.0f), glm::vec3(1.0f), 80.0f);

	glBindVertexArray(this->cube_vertex_array_handle);

	glDrawElements(GL_TRIANGLES , this->cube_mesh->GetNumberOfElements(), GL_UNSIGNED_INT , this->cube_mesh->GetTriangleIndexArray());

	this->DrawNormals(cube_mesh);*/

	// Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);
	do_texture_mapping = false;	
	this->do_displacement_mapping = false;
}

void Window::DrawScene()
{
	do_texture_mapping = false;

	// the point of the center of the picture frame / tablet
	glm::vec3 frame_center = glm::vec3(0.0f);

	glm::vec3 camera_location = glm::vec3(frame_center.x + 5.0f, frame_center.y + 5.77f, frame_center.z + 8.6603f);
	//glm::vec3 camera_location = glm::vec3(2.5f, 0.0f, 3.0f);

	glm::mat4 modelview_matrix = glm::lookAt(camera_location, frame_center, glm::vec3(0.0f, 1.0f, 0.0f));

	// these don't matter untill surface of revolution is added to scene
	glm::mat4 projection_matrix = glm::perspective(20.0f, ((float) this->width) / ((float) this->height), 0.1f, 100.0f);
	glm::mat3 normal_matrix = glm::inverse(glm::transpose(glm::mat3(modelview_matrix)));
	glm::mat4 mvp_matrix = projection_matrix * modelview_matrix;

	// draw the picture frame
	glm::mat4 picture_frame_mv = modelview_matrix;
	picture_frame_mv = glm::rotate(picture_frame_mv, 30.0f, glm::vec3(0.0f, 1.0f, 0.0f));
	picture_frame_mv = glm::rotate(picture_frame_mv, -30.0f, glm::vec3(1.0f, 0.0f, 0.0f));
	picture_frame_mv = glm::scale(picture_frame_mv, glm::vec3(3.0f, 1.75f, 0.125f));
	this->DrawCube(picture_frame_mv);

	// draw the table top
	glm::mat4 tabletop_mv = modelview_matrix;
	tabletop_mv = glm::translate(tabletop_mv, glm::vec3(1.0f, -0.875f, 0.0f));
	tabletop_mv = glm::scale(tabletop_mv, glm::vec3(10.0f, 0.25f, 5.0f));
	this->DrawCube(tabletop_mv);

	// draw the orange
#if 0
	glm::mat4 orange_mv = modelview_matrix;
	orange_mv = glm::rotate(orange_mv, 30.0f, glm::vec3(0.0f, 1.0f, 0.0f));
	orange_mv = glm::rotate(orange_mv, -30.0f, glm::vec3(1.0f, 0.0f, 0.0f));
	orange_mv = glm::translate(orange_mv, glm::vec3(0.0f, 0.0f, 10.0f));
	orange_mv = glm::scale(orange_mv, glm::vec3(0.05f, 0.05f, 0.05f));

	do_normal_mapping = true;

	//Set the material to orange
	shader->SetMaterial(glm::vec3(.13f), glm::vec3(1.0f, .549f, 0.0f), glm::vec3(1.0f, .549f, 0.0f), 80.0f);

	//Set initial value to matrices
	normal_matrix = glm::inverse(glm::transpose(glm::mat3(orange_mv)));
	mvp_matrix = projection_matrix * orange_mv;
		
	//set up the orange shader
	SetupShader(projection_matrix, orange_mv, normal_matrix, mvp_matrix);

	glBindVertexArray(this->planar_mesh_1_handle);
	glDrawElements(GL_TRIANGLES , this->planar_mesh1->GetNumberOfElements(), GL_UNSIGNED_INT , this->planar_mesh1->GetTriangleIndexArray());

	this->DrawNormals(planar_mesh1);

	//Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);
	do_normal_mapping = false;
#endif

	// Unbind vertexArray and program
	glBindVertexArray(0);
	glUseProgram(0);
	do_texture_mapping = false;
}

inline bool EVEN(int n)
{
	return ((n % 2) == 0);
}

inline bool ODD(int n)
{
	return ((n & 1) == 1);
}

void Window::ApplyCustomization(float (* function)(float), PlanarMesh * planarMesh)
{
	int x_density, y_density;
	planarMesh->GetDensity(x_density, y_density);
	float tr =  360.0f / ((float) x_density - 1);

	glm::vec4 p;
	glm::vec4 q;

	int y_start = 0;
	int y_end = y_density;

	for (int y = y_start; y < y_end; ++y)
	{
		glm::mat4 m(1.0f);
		glm::vec3 * outPointer = (planarMesh->GetOutArray() + x_density * y);
		p = glm::vec4((*function)(((float) y - y_start) / ((float) y_end - 1)), ((float) y - y_start) / ((float) y_end - 1) - 0.5f, 0.0f, 0.0f);
		//This is what actually does the revolution
		for (int x = 0; x < x_density; ++x)
		{
			q = m * p;
			*(outPointer++) = glm::vec3(q.x, q.y, q.z);
			m = glm::rotate(m, tr, glm::vec3(0.0f, 1.0f, 0.0f));
		}
	}

	// Make normals
	int left = -1;
	int right;
	int up = x_density;
	int down = -x_density;

	float top_radius = (*function)(0.0f);
	float bot_radius = (*function)(1.0f);

	for (int y = 0; y < y_density; y++)
	{
		glm::vec3 * outVertexPointer = (planarMesh->GetOutArray() + x_density * y + 1);
		glm::vec3 * outNormalPointer = (planarMesh->GetOutNormals() + x_density * y + 1);
		glm::vec3 * firstNormalPointer = (planarMesh->GetOutNormals() + x_density * y);

		for (int x = 1; x < x_density; x++)
		{
			right = (x < x_density - 1) ? 1 : -(x_density - 2);

			glm::vec3 normal(0.0f);

			if (y == 0 && top_radius == 0.0f)
				normal = glm::vec3(0.0f, 1.0f, 0.0f);
			else if (y == y_density - 1 && bot_radius == 0.0f)
				normal = glm::vec3(0.0f, -1.0f, 0.0f);
			else
			{
				// Row above
				if (y < y_density - 1)
				{
					if (y > 0)
						normal += glm::cross(glm::normalize(*(outVertexPointer + left) - *outVertexPointer) , glm::normalize(*(outVertexPointer + left + up) - *outVertexPointer));
					normal += glm::cross(glm::normalize(*(outVertexPointer + left + up) - *outVertexPointer) , glm::normalize(*(outVertexPointer + up) - *outVertexPointer));
					normal += glm::cross(glm::normalize(*(outVertexPointer + up) - *outVertexPointer) , glm::normalize(*(outVertexPointer + right) - *outVertexPointer));
				}
				if (y > 0)
				{
					normal += glm::cross(glm::normalize(*(outVertexPointer + down) - *outVertexPointer) , glm::normalize(*(outVertexPointer + left) - *outVertexPointer));
					normal += glm::cross(glm::normalize(*(outVertexPointer + down + right) - *outVertexPointer) , glm::normalize(*(outVertexPointer + down) - *outVertexPointer));
					if (y < y_density - 1)
						normal += glm::cross(glm::normalize(*(outVertexPointer + right) - *outVertexPointer) , glm::normalize(*(outVertexPointer + down + right) - *outVertexPointer));
				}
			}

			normal = glm::normalize(normal);

			if (x == x_density - 1)
			{
				*firstNormalPointer = -normal;
			}

			*outNormalPointer = -normal;
			outNormalPointer++;
			outVertexPointer++;
		}
	}

}

 void Window::SetTexture()
{
	//Link in DM map
	if (do_displacement_mapping)
	{
		glUniform1i(shader->displacement_map_handle, 4);
		glActiveTexture(GL_TEXTURE0 + 4);
		//glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[previousColorAttachment]);
		glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[0]);
	}

	//Determine texture
	switch(this->mode)
	{
		case(ORANGE_BEAUTY):
			glUniform1i(shader->normal_map_handle, 0);
			this->normal_map_container.Bind(0);
			break;
		case(BOTTLE_BEAUTY):
			glUniform1i(shader->texture_map_handle, 1);
			this->buckyTex_container.Bind(1);
			break;
		case(PICTURE_FRAME_BEAUTY):
			if (firstDraw || wallpaperSwitched)
			{
				wallpaperSwitched = false;
				glUniform1i(shader->texture_map_handle, 3);
				switch(this->wallpaper)
				{
				case(WALLPAPER_1):
					this->wallpaper1_container.Bind(3);
					break;
				case(WALLPAPER_2):
					this->wallpaper2_container.Bind(3);
					break;
				case(WALLPAPER_3):
					this->wallpaper3_container.Bind(3);
					break;
				case(DISPLACEMENT_MAP):
					glActiveTexture(GL_TEXTURE0 + 3);
					if (!do_displacement_mapping)
					{
						glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[doublePreviousColorAttachment]);

					}

					else
					{
						glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[previousColorAttachment]);
					}
					break;
				}
			}

			else
			{
				glUniform1i(shader->texture_map_handle, 3);
				glActiveTexture(GL_TEXTURE0 + 3);

				if (!do_displacement_mapping)
					//glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[previousColorAttachment]);
					//glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[1]);
					glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[0]);
				else
					//glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[doublePreviousColorAttachment]);
					//glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[0]);
				//this->wallpaper1_container.Bind(3);
				glBindTexture(GL_TEXTURE_2D, fbo.texture_handles[0]);
			}
			break;

		case (STILL_LIFE):
		{	
			glUniform1i(shader->texture_map_handle, 2);
			this->wood1_container.Bind(2);
			break;
		}
	}
}

void Window::UpdateSource(glm::vec2 position)
{	
	this->sourcePosition = position;
}

void Window::UpdateDestination(glm::vec2 position)
{
	this->destinationPosition = position;
}

void Window::CyclecurrentColorAttachment()
{
	doublePreviousColorAttachment = previousColorAttachment;
	previousColorAttachment = currentColorAttachment;

	if (currentColorAttachment == 2) 
	{
		currentColorAttachment = 0;
	}

	else
	{
		currentColorAttachment++;
	}
}
void Window::SwitchWallpaper()
{
	wallpaperSwitched = true;
	switch (this->wallpaper)
	{
	case (WALLPAPER_1):
		this->wallpaper = WALLPAPER_2;
		break;
	case (WALLPAPER_2):
		this->wallpaper = WALLPAPER_3;
		break;
	case (WALLPAPER_3):
		this->wallpaper = WALLPAPER_1;
		break;
	case (DISPLACEMENT_MAP):
		this->wallpaper = WALLPAPER_1;
		break;
	}

}

void Window::DrawNormals(PlanarMesh * planarMesh)
{

	//Delete since it is legacy GL?
	float theta = ((float) this->x) / ((float) this->width) * 360.0f - 180.0f;
	float rho = ((float) this->y) / ((float) this->height) * 360.0f - 180.0f;
	if (this->draw_normals)
	{
		glDisable(GL_LIGHTING);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(20, ((double) this->width) / ((double) this->height), 1, 10);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(0, 0.0, 5.5, 0, 0, 0, 0, 1, 0);
		glRotated(theta, 0, 1, 0);
		glRotated(rho, 1, 0, 0);
		glPushMatrix();
		glScalef(0.5f, 0.5f, 0.5f);
		this->Axes();
		glPopMatrix();
		planarMesh->Draw(PlanarMesh::OutArray, true);
	}

}

void Window::Axes()
{
		GLboolean lighting_is_enabled = glIsEnabled(GL_LIGHTING);
		glDisable(GL_LIGHTING);
		glBegin(GL_LINES);
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex3f(0.0f, 0.0f, 0.0f);
		glVertex3f(1.0f, 0.0f, 0.0f);
		glColor3f(0.0f, 1.0f, 0.0f);
		glVertex3f(0.0f, 0.0f, 0.0f);
		glVertex3f(0.0f, 1.0f, 0.0f);
		glColor3f(0.0f, 0.0f, 1.0f);
		glVertex3f(0.0f, 0.0f, 0.0f);
		glVertex3f(0.0f, 0.0f, 1.0f);
		glEnd();
		if (lighting_is_enabled)
			glEnable(GL_LIGHTING);
}
